#include <iostream>
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>
#include <cassert>

using namespace std;

void PrintSig(sigset_t &pending)
{
    // 我们这里不能直接打印pending
    // 它是一个结构体,不能打印
    // 穷举所有信号
    cout << "Pending bitmap: ";
    for (int signo = 31; signo > 0; signo--)
    {
        if (sigismember(&pending, signo))
        {
            cout << "1";
        }
        else
        {
            cout << "0";
        }
    }
    cout << endl;
}

void handler(int signo)
{
    sigset_t pending;
    sigemptyset(&pending);
    // 此时我们正在处理2号信号哟!正在递达中
    int n = sigpending(&pending); // 获取pending位图
    assert(n == 0);

    // 打印所有的pending位图中的信号
    cout << "抵达中..." << endl;
    PrintSig(pending);//查看此时的比特位
    // 0:递达之前，pending 2号已经被清0
    // 1:pending 2号已经被清0,一定是在递达之后
    cout << signo << " 2号信号被递达处理..." << endl;
}

int main()
{
    signal(2, handler);

    // 1.屏蔽2号信号
    sigset_t block, oblock;
    sigemptyset(&block);  // 屏蔽信号集清空
    sigemptyset(&oblock); // 屏蔽信号集清空

    // 0.for test: 如果我们屏蔽了所以信号呢？进程不会退，杀不掉
    // for(int signo = 1; signo <= 31; signo++)
    // sigaddset(&block,signo);//把所有信号添加到屏蔽信号
    // 目前根本就没有设置当前进程的PCB
    sigaddset(&block, 2);
    // 1.1 开始屏蔽所有信号，其实就是设置进入内核中
    int n = sigprocmask(SIG_SETMASK, &block, &oblock);
    assert(n == 0);

    cout << "block 2 signal success" << endl;
    int cnt = 0;
    while (true)
    {
        // 2.获取pending位图
        sigset_t pending;
        sigemptyset(&pending);
        n = sigpending(&pending); // 获取pending位图
        assert(n == 0);

        // 3.打印所有的pending位图中的信号
        PrintSig(pending);
        cnt++;

        // 看到pending 2号信号 由1变会0，并且看到2号信号递达的过程
        // 4.解除对2号信号的屏蔽
        if (cnt == 5)
        {
            cout << "成功解除对2号信号的屏蔽" << endl;

            n = sigprocmask(SIG_UNBLOCK, &block, &oblock); // 2号信号会被立即递达，并执行默认动作
            assert(n == 0);
        }
        sleep(1);
    }

    return 0;
}

/*
int main()
{
    // 有没有涉及到将数据设置进内核中呢？没有
    // sigset_t数据类型,和我们的基本数据类型和自定义类型没有差别
    sigset_t s; //用户在栈上开辟空间,下列操作只是修改变量
    sigemptyset(&s);
    sigaddset(&s, 2);

    return 0;
}
*/

/*
int main()
{
    pid_t id = fork();
    if(id == 0)
    {
        sleep(2);
        int a = 10;
        a /= 0; // 故意异常，收到SIGFPE -> Core
        exit(0);// 退出码设置为0
    }

    //father
    int status;
    pid_t rid = waitpid(id,&status,0);
    if(rid > 0) //等待成功
    {
        cout << "exit code: " << ((status>>8) & 0xFF) << endl;
        cout << "exit signal: " << (status & 0x7F) << endl;
        cout << "core dump: " << ((status>>7) & 0x1) << endl;
    }
    return 0;
}
*/

/*
int main()
{
    cout << "run begin..." << endl;
    int a = 10;
    a /= 0; //SIGFPE -> Core
    cout << "run end..." << endl;
    while(true) sleep(1);
    return 0;
}
*/
